﻿using System;
using System.Reflection;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace OrbClientCacher
{
	
	/// <summary>
	/// Tray-Anwendung zur Steuerung und Überwachung des OrbClientCachers
	/// </summary>
	public class OrbClientCacherTray : Form, IObserveCacher
	{

		/// <summary>
		/// Referenz auf das TrayIcon
		/// </summary>
		private NotifyIcon trayIcon;

		/// <summary>
		/// Referenz auf das TrayMenu
		/// </summary>
		private ContextMenu trayMenu;
		
		/// <summary>
		/// Referenz auf den Cacher
		/// </summary>
		private OrbClientCacher clientCacher;
		
		/// <summary>
		/// Name des Tools
		/// </summary>
		private string toolName;

		/// <summary>
		/// Versionsnummer des Tools
		/// </summary>
		private string version;

		/// <summary>
		/// Konstruktor
		/// </summary>
		public OrbClientCacherTray()
		{
			// About-Informationen
			this.toolName = Assembly.GetExecutingAssembly().GetName().Name;
			this.version = Assembly.GetExecutingAssembly().GetName().Version.ToString();
			
			this.InitializeComponent();
			this.InitTrayMenu();
			this.InitTrayIcon();
			this.InitClientCacher();
		}

		/// <summary>
		/// Caching-Mechanismus initialisieren
		/// </summary>
		private void InitClientCacher()
		{
			this.clientCacher = new OrbClientCacher();
			this.clientCacher.AddObserver(this);
			Task.Factory.StartNew(new Action(this.clientCacher.Start));
		}

		/// <summary>
		/// Tray-Icon initialisieren
		/// </summary>
		private void InitTrayIcon()
		{			
			this.trayIcon = new NotifyIcon();
			this.trayIcon.Text = string.Format("{0} - {1}", this.toolName, "Idle");
			this.trayIcon.Icon = Properties.Resources.TrayIcon;
			this.trayIcon.ContextMenu = this.trayMenu;
			this.trayIcon.Visible = true;
		}

		private MenuItem index;
		private MenuItem status;

		/// <summary>
		/// Tray-Menu initialisieren
		/// </summary>
		private void InitTrayMenu()
		{
			this.trayMenu = new ContextMenu();

			MenuItem version = new MenuItem(this.toolName + " " + this.version);
			this.status = new MenuItem("Idle");
			this.index = new MenuItem("Index 0 of 0 - 100%");
			MenuItem recache = new MenuItem("ReCache", OnRecache);
			MenuItem settings = new MenuItem("Settings", OnSettings);
			MenuItem exit = new MenuItem("Exit", OnExit);

			version.Enabled = false;
			status.Enabled = false;
			index.Enabled = false;

			this.trayMenu.MenuItems.Add(version);
			this.trayMenu.MenuItems.Add("-");
			this.trayMenu.MenuItems.Add(status);
			this.trayMenu.MenuItems.Add(index);
			this.trayMenu.MenuItems.Add(recache);
			this.trayMenu.MenuItems.Add(settings);
			this.trayMenu.MenuItems.Add("-");
			this.trayMenu.MenuItems.Add(exit);
		}

		/// <summary>
		/// Wird bei Beendigung des Programmes aufgerufen
		/// </summary>
		/// <param name="isDisposing"></param>
		protected override void Dispose(bool isDisposing)
		{
			if (isDisposing)
				this.trayIcon.Dispose();

			base.Dispose(isDisposing);
		}

		#region ObserverImplementation
		
		/// <summary>
		/// Benachrichtigung über die größe des Indexes
		/// </summary>
		/// <param name="size"></param>
		public void NotifyIndexSize(int size)
		{
			this.indexSize = size;
			this.CalculateProgress();
		}
		
		/// <summary>
		/// Benachrichtigt über den Fortschritt des Caches
		/// </summary>
		/// <param name="progress"></param>
		public void NotifyProgress(int progress)
		{
			this.indexProgress = progress;
			this.CalculateProgress();
		}

		/// <summary>
		/// Benachrichtigung über den Status des Cachers
		/// </summary>
		/// <param name="status"></param>
		public void NotifyState(string status)
		{
			this.status.Text = status;
			this.trayIcon.Text = string.Format("{0} - {1}", this.toolName, status);
		}

		private int indexSize;
		private int indexProgress;

		/// <summary>
		/// Fortschritt berechnen
		/// </summary>
		private void CalculateProgress()
		{
			if (this.indexSize <= 0)
			{
				this.index.Text = "Index 0 of 0 - 100%";
				return;
			}

			double percent = ((double)this.indexProgress / this.indexSize);
			this.index.Text = string.Format("Index {0:d} of {1:d} - {2:P0}", this.indexProgress, this.indexSize, percent);
		}
		#endregion

		#region TrayMenuEvents
		
		/// <summary>
		/// Startet den Cache-Vorgang erneut
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void OnRecache(object sender, EventArgs e)
		{
			this.clientCacher.ReCache();
		}

		/// <summary>
		/// Startet die Konfigurationsoberfläche
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void OnSettings(object sender, EventArgs e)
		{
			Settings s = new Settings();
			this.Invoke(new Action(s.Show));
		}

		/// <summary>
		/// Beendet das Programm
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void OnExit(object sender, EventArgs e)
		{
			this.clientCacher.Stop();
			Application.Exit();
		}
		#endregion

		/// <summary>
		/// Wird beim start des Programmes ausgeführt
		/// </summary>
		/// <param name="e"></param>
		protected override void OnLoad(EventArgs e)
		{
			base.Visible = false;
			base.ShowInTaskbar = false;
			base.Hide();
			base.OnLoad(e);
		}

		[STAThread]
		public static void Main(string[] args)
		{
			Application.Run(new OrbClientCacherTray());
		}

		/// <summary>
		/// Initialisierung der (teils versteckten) GUI
		/// </summary>
		private void InitializeComponent()
		{
			this.SuspendLayout();
			this.ClientSize = new System.Drawing.Size(292, 273);
			this.Name = "OrbClientCacherTray";
			this.ResumeLayout(false);
		}
	}
}
